Route 53 Application Recovery Controllerを試した
中山(順)です
先日、Route 53 Application Recovery Controllerなる機能がリリースされました。
Amazon Route 53 announces Route 53 Application Recovery Controller
この記事では環境構築および動作確認を実施した結果をまとめてみました。
Route 53 Application Recovery Controllerとは
サービスを運用するにあたり、「可用性」は重要なテーマの一つです。 設計の際には、障害が表面化しないようにコンポーネントを冗長化したり障害が発生した時に速やかに復旧できるように工夫をすると思います。
具体的には、特定のリージョンにおいて1つのVPCをベースにSubnet / ALB / AutoScaling / RDS等のリソースを複数のアベイラビリティーゾーンに跨がってプロビジョニングするような設計がよくあると思います。 もっと高い可用性を求める場合には、API Gateway / Lambda / DynamoDBなどのリージョナルなサービスを利用したり、VPC上に構成した環境を複数のリージョンの展開する、といったパターンがあると思います。 このあたりは多くの環境で考慮できていると思います。
しかし、運用フェーズにおいて「障害発生時に正しくリカバリーのオペレーションを実行できるのか」「冗長化されたコンポーネントは適切な状態に維持できているのか」という問いに自信をもってYESと答えることはできますか? どれだけ設計やリリース時の実装が適切でも、オペレーションを繰り返すうちに設計時のパラメーターから意図せず乖離してしまう事もあると思います。 また、不十分なドキュメンテーションや担当者の変更に伴う不十分な引き継ぎにより必要な情報が失われ、いざという時に障害の発生時に正しく復旧する手順が分からなくなるということもあるのではないでしょうか。
今回リリースされたRoute 53 Application Recovery Controllerでは、システムを構成するリソースの設定・状態をチェックしたり、柔軟かつ安全なルーティング制御機能を提供します。
Route 53 Application Recovery Controllerでは、"Readiness check"および"Routing control"の2つの機能を提供します。 ちなみに、APIも機能毎に分かれています。 厳密には、"Recovery Readiness API"、"Recovery Control Config API"(Routing controlの設定に関するAPI)、"Recovery Control API"(Routing controlのステート操作に関するAPI)の3種類のAPIが提供されています。
What is recovery readiness in Amazon Route 53 Application Recovery Controller?
What is recovery control configuration in Amazon Route 53 Application Recovery Controller?
Readiness check
冗長化されたリソースの間のドリフト(構成の差異)や容量不足等をチェックしてくれる機能です。
例えば、ALB / AutoScaling Group / DynamoDBを利用して動作するアプリケーションを2つのリージョンに展開しているとします。 その際、2つのリージョンに展開するリソースの状態等をリソースの種類毎に比較・評価し、トラフィックをルーティングしても問題ない状態か確認することができます。
Routing control
Route 53 Health checkおよびHealth checkを利用するRouting policyを設定したRecord setと連携し、トラフィックを制御する機能です。
以前からRoute 53のヘルスチェック機能でエンドポイントの応答を監視でき、結果に応じてDNSフェールオーバーを自動化することができました。 機能の名称から似たような機能と思われるかもしれません。 しかし、このRouting controlはAPI経由でエンドポイントをON/OFFするスイッチのようなもので、エンドポイントの健全性を評価しているわけではありません。
例えば、ALBをエンドポイントとするアプリケーションスタックを2つのリージョンにプロビジョニングしているとします。 その場合、各エンドポイントに対応するRouting control / Health check / DNS Record(フェールオーバーなどのルーティングポリシー付き)を作成することで、対応するエンドポイントへのルーティングをON/OFFできます。
ちなみに、誤ってルーティング先をすべてOFFにするようなオペレーションを行った場合でもサービスの継続が可能となるようなセーフガード的な機能も実装されています。
・・・と、ここまで簡単に機能の概要を説明しましたが、正直よく分からないと思いますので実際に触りながら理解していこうと思います(正直、とっつきにくかった)。
やってみた
管理対象のアプリケーションをデプロイ
機能を確認する前に、管理対象となるアプリケーションをデプロイします。
今回は、公式ブログでも紹介されていたサンプルアプリケーションを利用します。
Introducing Amazon Route 53 Application Recovery Controller
以下の図(公式ブログより引用)にあるとおり、「2つのリージョンに跨がったALBとAutoScaling Group」および「DynamoDB Global Table」「Route 53 Hosted Zone」をデプロイします。 この環境に対してRoute 53 Application Recovery Controllerを適用します。
Hosted Zone以外のリソースは、先に挙げたGitHubリポジトリにあるCDKのコードでデプロイできます。
なお、Cloud9環境でデプロイする場合には、Node.jsのバージョンなどにご注意ください。 以下のコマンドは、Cloud9 (Amazon Linux 2) で環境をデプロイしたときの手順です。
# Update Node.js nvm install node # Install CDK 2 if not done already npm install -g aws-cdk@next # Install the new dependencies npm install # Clone this repository if not done already git clone https://github.com/sebsto/tictactoe-cdk.git cd tictactoe-cdk # the very first time (one time operation) cdk bootstrap # deploy the app cdk deploy --all --outputs-file out.json
CDKでデプロイされたリソースは以下の通りです。 これらの情報は、設定時に利用します。
cat out.json
{ "TictactoeAppCdkStack-us-east-1": { "LoadBalancerDNSName": "Ticta-TicTa-YWMTPCCQ3W7E-1302178901.us-east-1.elb.amazonaws.com", "HostedZoneLoadBalancer": "Z35SXDOTRQ7X7K", "ARNAutoScalingGroup": "arn:aws:autoscaling:us-east-1:xxxxxxxxxxxx:autoScalingGroup:*:autoScalingGroupName/TictactoeAppCdkStack-us-east-1-TicTacToeASGCBDED12E-7VX164PP89X6", "ARNLoadBalancer": "arn:aws:elasticloadbalancing:us-east-1:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-YWMTPCCQ3W7E/b6231aee3fc0f4f2" }, "TictactoeAppCdkStack-us-west-2": { "LoadBalancerDNSName": "Ticta-TicTa-75WLM88UNNBN-1655711362.us-west-2.elb.amazonaws.com", "HostedZoneLoadBalancer": "Z1H1FL5HABSF5", "ARNAutoScalingGroup": "arn:aws:autoscaling:us-west-2:xxxxxxxxxxxx:autoScalingGroup:*:autoScalingGroupName/TictactoeAppCdkStack-us-west-2-TicTacToeASGCBDED12E-1O7BWG3Y3TL21", "ARNLoadBalancer": "arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-75WLM88UNNBN/2514249eff5f0a8c" }, "TictactoeDatabaseCdkStack": { "ARNDatabaseTable": "arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/Games" } }
AWSリソース・用語の解説
Route 53 Application Recovery Controllerの提供に併せて多くのリソースが新しく定義されています。 作業の前に各リソースの役割をご紹介します。
主要なリソースは以下の通りです。
- Readiness check
- Cell
- Recovery group
- Resource set
- Readiness check
- Readiness rule
- Routing control
- Cluster
- Routing control
- Control panel
- Safety rule
Cell
アプリケーションが独立して機能するために必要なリソースをグルーピングするリソースです。 例えば、(リージョンレベルで冗長化する場合)1つのリージョンに展開された "ALB" + "AutoScaling Group" などです。
Cellはリージョン単位に区切る必要はなく、アベイラビリティゾーン単位やより細かい単位で区切ることも可能です。 また、Cellは入れ子にすることもできます。
Recovery group
Cellをグルーピングするリソースです。 1システム = 1 Recovery groupと捉えれば良いと思います。
Resource set
Cellを跨がった同じ役割を担うリソースをグルーピングするものです。 1つのResource setには同じ種類のリソースを関連付けることができます。 例えば、Cellが"ALB" + "AutoScaling Group" で構成されていた場合、ALB用のResource setに各CellのALBを関連付けます。 AutoScaling Groupについても同様です。
Readiness check
Readiness checkは、Resource Setに関連付けたリソースの構成が適切かを検証するためのリソースです。 どのような評価を行うかは、後述するReadiness ruleとして事前定義されています。 サポートされているリソースは公式ドキュメントをご確認ください。
Readiness rule
Resource setに関連付けたリソースが適切に構成されているかを評価するためのルールです。 リソースの種類毎に検証ルールが事前定義されており、ユーザーが独自に定義するものではありません(現時点では)。 詳細はドキュメントを確認してください。
Readiness rules in Route 53 Application Recovery Controller
Cluster
ここからはRouting controlに関するリソースです。
Clusterはルーティングを制御するためのエンドポイントを提供するリソースです。 特定のリージョン全体に影響を与えるような障害が発生した場合に、いざルーティングを変更しようとしたらそのサービス・APIが障害で使えなかったら話になりませんよね。 クラスターを作成することで後述するRouting controlというリソースを操作するためのエンドポイントが5つのリージョンに跨がって展開され、いずれかのエンドポイントを利用してルーティングを制御することができます。 エンドポイントの利用方法は後述します。
Routing control
Route 53 Health checkと連携し、Failover routing policy等を設定したレコードのエンドポイントへのルーティングを制御します。 Route 53 Health checkに対してRouting controlを関連付けることで、Routing controlのON/OFFがHealth checkの結果と連動します。 それにより、容易にDNSフェールオーバーを実行できます。
なお、Readiness checkの結果とRouting controlが連動しません。
Control panel
Routing controlをグルーピングするためのリソースです。 Control panelは特定のクラスターに所属します。 Cluster作成時点でデフォルトのControl panelが存在するので、それを使っても問題ありません。 個人的にはデフォルト・暗黙的に作成されるリソースは使いたくない派です。
Safety rule
Routing controlに対する誤ったオペレーションでサービスが停止することを防止するための仕組みです。 すべてのエンドポイントに対するRouting controlをOFFにしてしまうようなオペレーションを行っても、ルーティングが完全に止まらないようセーフガード的な役割を果たします。
リソースまとめ
図にするとこんな感じかと思います。 各リソースの関係についてはこの後の設定手順・設定項目を見て頂ければ理解できるようになると思います。たぶん。
構築
それでは構築作業を進めます。 工程は以下の通りです。
- Cellの作成
- (今回は管理対象のアプリがリージョンレベルで冗長化しているので)リージョン毎に作成
- Recovery Groupの作成
- 作成したCellを関連付け
- Resource setの作成
- ALB / AutoScaling Group / DynamoDB毎に作成
- Resource setにリソースを関連付ける際に対応するCellに関連付ける(DynamoDB Global Tableは実質グローバルリソースなのでCellには関連付けない)
- Readiness checkの作成
- Resource set毎に作成
- Clusterの作成
- Control panelの作成
- 作成したClusterに関連付け
- Routing controlの作成
- ALB毎に作成
- Safety ruleの作成
- 作成したRouting controlおよびControl panelを関連付け
- Health checkの作成
- Routing control毎に作成
- Record setの作成
- プライマリーリージョン用のALB EndpointとHealth checkを利用し、Failover routing policyのプライマリーレコードを作成
- 残りのALB EndpointとHealth checkを利用し、Failover routing policyのセカンダリレコードを作成
サンプルアプリ用のCDKコードを含むリポジトリにはCFnテンプレートも用意されているのですが、リソースの設定項目を把握・理解するためにもAWS CLIで設定を行います。
aws --version
aws-cli/2.2.28 Python/3.8.8 Linux/4.14.238-182.422.amzn2.x86_64 exec-env/CloudShell exe/x86_64.amzn.2 prompt/off
Cellの作成
まずCellを作成します。
まずはプライマリーリージョン用のCellを作成します。
aws route53-recovery-readiness create-cell \ --cell-name primary-cell
{ "CellArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/primary-cell", "CellName": "primary-cell", "Cells": [], "ParentReadinessScopes": [], "Tags": {} }
続けて、セカンダリーリージョン用のCellを作成します。
aws route53-recovery-readiness create-cell \ --cell-name secondary-cell
{ "CellArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/secondary-cell", "CellName": "secondary-cell", "Cells": [], "ParentReadinessScopes": [], "Tags": {} }
図にするとこんな感じです。
Recovery groupの作成
Recovery groupを作成します。 その際、先に作成したCellをすべて関連付けます。
aws route53-recovery-readiness create-recovery-group \ --cells "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/primary-cell" "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/secondary-cell" \ --recovery-group-name TicTacToe-recovery-group
{ "Cells": [ "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/primary-cell", "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/secondary-cell" ], "RecoveryGroupArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:recovery-group/TicTacToe-recovery-group", "RecoveryGroupName": "TicTacToe-recovery-group", "Tags": {} }
Resource setの作成
Resource setを作成します。 今回のサンプルアプリケーションは、ALB / Autoscaling Group / DynamoDBの3種類のリソースで構成されています。 それに合わせて3つのResource setを作成します。
まずはALB用のResource setを作成します。 作成時にリソースがどのCellに所属するかも指定します。 今回はus-east-1(バージニアリージョン)のリソースをプライマリー、us-west-2(オレゴンリージョン)のリソースをセカンダリーとします。
ALB_RESOURCES_FILE_NAME='ALBResources.json' cat << EOF > ${ALB_RESOURCES_FILE_NAME} [ { "ReadinessScopes": ["arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/primary-cell"], "ResourceArn": "arn:aws:elasticloadbalancing:us-east-1:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-YWMTPCCQ3W7E/b6231aee3fc0f4f2" }, { "ReadinessScopes": ["arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/secondary-cell"], "ResourceArn": "arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-75WLM88UNNBN/2514249eff5f0a8c" } ] EOF aws route53-recovery-readiness create-resource-set \ --resource-set-name alb-resource-set \ --resource-set-type AWS::ElasticLoadBalancingV2::LoadBalancer \ --resources file://${ALB_RESOURCES_FILE_NAME}
{ "ResourceSetArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:resource-set/alb-resource-set", "ResourceSetName": "alb-resource-set", "ResourceSetType": "AWS::ElasticLoadBalancingV2::LoadBalancer", "Resources": [ { "ReadinessScopes": [ "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/primary-cell" ], "ResourceArn": "arn:aws:elasticloadbalancing:us-east-1:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-YWMTPCCQ3W7E/b6231aee3fc0f4f2" }, { "ReadinessScopes": [ "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/secondary-cell" ], "ResourceArn": "arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-75WLM88UNNBN/2514249eff5f0a8c" } ], "Tags": {} }
AutoScaling Groupについても同様に設定します。
ASG_RESOURCES_FILE_NAME='ASGResources.json' cat << EOF > ${ASG_RESOURCES_FILE_NAME} [ { "ReadinessScopes": ["arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/primary-cell"], "ResourceArn": "arn:aws:autoscaling:us-east-1:xxxxxxxxxxxx:autoScalingGroup:*:autoScalingGroupName/TictactoeAppCdkStack-us-east-1-TicTacToeASGCBDED12E-7VX164PP89X6" }, { "ReadinessScopes": ["arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/secondary-cell"], "ResourceArn": "arn:aws:autoscaling:us-west-2:xxxxxxxxxxxx:autoScalingGroup:*:autoScalingGroupName/TictactoeAppCdkStack-us-west-2-TicTacToeASGCBDED12E-1O7BWG3Y3TL21" } ] EOF aws route53-recovery-readiness create-resource-set \ --resource-set-name asg-resource-set \ --resource-set-type AWS::AutoScaling::AutoScalingGroup \ --resources file://${ASG_RESOURCES_FILE_NAME}
{ "ResourceSetArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:resource-set/asg-resource-set", "ResourceSetName": "asg-resource-set", "ResourceSetType": "AWS::AutoScaling::AutoScalingGroup", "Resources": [ { "ReadinessScopes": [ "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/primary-cell" ], "ResourceArn": "arn:aws:autoscaling:us-east-1:xxxxxxxxxxxx:autoScalingGroup:*:autoScalingGroupName/TictactoeAppCdkStack-us-east-1-TicTacToeASGCBDED12E-7VX164PP89X6" }, { "ReadinessScopes": [ "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:cell/secondary-cell" ], "ResourceArn": "arn:aws:autoscaling:us-west-2:xxxxxxxxxxxx:autoScalingGroup:*:autoScalingGroupName/TictactoeAppCdkStack-us-west-2-TicTacToeASGCBDED12E-1O7BWG3Y3TL21" } ], "Tags": {} }
DynamoDB Global Tableは特定のリージョンに依存していないので、Cellには関連付けず、Recovery groupに関連付けます。
DDB_RESOURCES_FILE_NAME='DDBResources.json' cat << EOF > ${DDB_RESOURCES_FILE_NAME} [ { "ReadinessScopes": ["arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:recovery-group/TicTacToe-recovery-group"], "ResourceArn": "arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/Games" } ] EOF aws route53-recovery-readiness create-resource-set \ --resource-set-name ddb-resource-set \ --resource-set-type AWS::DynamoDB::Table \ --resources file://${DDB_RESOURCES_FILE_NAME}
{ "ResourceSetArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:resource-set/ddb-resource-set", "ResourceSetName": "ddb-resource-set", "ResourceSetType": "AWS::DynamoDB::Table", "Resources": [ { "ReadinessScopes": [ "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:recovery-group/TicTacToe-recovery-group" ], "ResourceArn": "arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/Games" } ], "Tags": {} }
Readiness checkの作成
直前で作成した各Resource setに対応する形でReadiness checkを作成します。
まずはALB用のReadiness checkを作成します。
aws route53-recovery-readiness create-readiness-check \ --readiness-check-name alb-readiness-check \ --resource-set-name alb-resource-set
{ "ReadinessCheckArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:readiness-check/alb-readiness-check", "ReadinessCheckName": "alb-readiness-check", "ResourceSet": "alb-resource-set", "Tags": {} }
AutoScaling Group用も同じ要領で作成します。
aws route53-recovery-readiness create-readiness-check \ --readiness-check-name asg-readiness-check \ --resource-set-name asg-resource-set
{ "ReadinessCheckArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:readiness-check/asg-readiness-check", "ReadinessCheckName": "asg-readiness-check", "ResourceSet": "asg-resource-set", "Tags": {} }
DynamoDBも同様です。
aws route53-recovery-readiness create-readiness-check \ --readiness-check-name ddb-readiness-check \ --resource-set-name ddb-resource-set
{ "ReadinessCheckArn": "arn:aws:route53-recovery-readiness::xxxxxxxxxxxx:readiness-check/ddb-readiness-check", "ReadinessCheckName": "ddb-readiness-check", "ResourceSet": "ddb-resource-set", "Tags": {} }
チェック結果は最後に確認します。
図にするとこんな感じです。
Readiness checkに関する設定は以上です。
Clusterの作成
ここからはRouting control用の設定となります。
まずはClusterを作成します。
aws route53-recovery-control-config create-cluster \ --cluster-name cluster
{ "Cluster": { "ClusterArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:cluster/ce43adf8-dc71-4994-be86-50d13569def5", "Name": "cluster", "Status": "PENDING" } }
作成完了後、Routing controlの操作に利用できるエンドポイントを確認できます。
aws route53-recovery-control-config describe-cluster \ --cluster-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:cluster/ce43adf8-dc71-4994-be86-50d13569def5"
{ "Cluster": { "ClusterArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:cluster/ce43adf8-dc71-4994-be86-50d13569def5", "ClusterEndpoints": [ { "Endpoint": "https://72e4802e.route53-recovery-cluster.us-west-2.amazonaws.com/v1", "Region": "us-west-2" }, { "Endpoint": "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1", "Region": "ap-northeast-1" }, { "Endpoint": "https://7b2076cf.route53-recovery-cluster.us-east-1.amazonaws.com/v1", "Region": "us-east-1" }, { "Endpoint": "https://2517c6b0.route53-recovery-cluster.eu-west-1.amazonaws.com/v1", "Region": "eu-west-1" }, { "Endpoint": "https://d8da50f8.route53-recovery-cluster.ap-southeast-2.amazonaws.com/v1", "Region": "ap-southeast-2" } ], "Name": "cluster", "Status": "DEPLOYED" } }
Control panelの作成
Control panelを作成します。 この後に作成するRouting controlをグルーピングするリソースです。 Control Panelには1つのシステム (= Recovery group) に関連するRouting controlをまとめるとよいのではないでしょうか。
Clusterの作成時にDefaultのControl Panelが作成されるので新規作成は必須ではないのですが、今回はあえて作成します。
aws route53-recovery-control-config create-control-panel \ --cluster-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:cluster/ce43adf8-dc71-4994-be86-50d13569def5" \ --control-panel-name TicTacToe-control-panel
{ "ControlPanel": { "ClusterArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:cluster/ce43adf8-dc71-4994-be86-50d13569def5", "ControlPanelArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72", "DefaultControlPanel": false, "Name": "TicTacToe-control-panel", "RoutingControlCount": 0, "Status": "PENDING" } }
Routing controlの作成
2つのALB Endpointに対応するRouting controlを作成します。 なお、既に書きましたがRouting controlはHealth checkのステータスを操作するためのスイッチであり、Readiness check等の結果と連動するわけではありません。
まずはプライマリーエンドポイント用のRouting controlを作成します。
aws route53-recovery-control-config create-routing-control \ --cluster-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:cluster/ce43adf8-dc71-4994-be86-50d13569def5" \ --control-panel-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72" \ --routing-control-name primary-routing-control
{ "RoutingControl": { "ControlPanelArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72", "Name": "primary-routing-control", "RoutingControlArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd", "Status": "PENDING" } }
続けてセカンダリエンドポイント用のRouting controlを作成します。
aws route53-recovery-control-config create-routing-control \ --cluster-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:cluster/ce43adf8-dc71-4994-be86-50d13569def5" \ --control-panel-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72" \ --routing-control-name secondary-routing-control
{ "RoutingControl": { "ControlPanelArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72", "Name": "secondary-routing-control", "RoutingControlArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44", "Status": "PENDING" } }
作成直後のRouting controlのステータスはOFFになっています。 なお、Routing controlの状態確認および操作は"aws route53-recovery-cluster"コマンドを利用する必要があり、なおかつEndpoint URLをCluster作成時に確認したものにする必要があります。 今回は東京リージョンのエンドポイントを利用します(東京リージョンを使うことに深い理由はありません)。
aws route53-recovery-cluster get-routing-control-state \ --routing-control-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd" \ --endpoint-url "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1" \ --region ap-northeast-1
{ "RoutingControlArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd", "RoutingControlState": "Off" }
Safety Ruleの作成
次にSafety ruleを作成します。
直前に作成したControl panelおよびRouting controlを関連付けます。 また、今回は「すくなくとも1つ以上のRouting controlがONである必要がある」というルールを設定します。 挙動は後ほど確認します。
SAFETY_RULE_FILE_NAME='SafetyRule.json' cat << EOF > ${SAFETY_RULE_FILE_NAME} { "AssertedControls": [ "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd", "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44" ], "ControlPanelArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72", "Name": "safety-rule", "RuleConfig": { "Inverted": false, "Threshold": 1, "Type": "ATLEAST" }, "WaitPeriodMs": 5000 } EOF aws route53-recovery-control-config create-safety-rule \ --assertion-rule file://${SAFETY_RULE_FILE_NAME}
{ "AssertionRule": { "AssertedControls": [ "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd", "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44" ], "ControlPanelArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72", "Name": "safety-rule", "RuleConfig": { "Inverted": false, "Threshold": 1, "Type": "ATLEAST" }, "SafetyRuleArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/safetyrule/1c2da713a77e46f1", "Status": "PENDING", "WaitPeriodMs": 5000 } }
Health checkの作成
Routing controlと連動させるHealth checkを作成します。 改めて述べますが、ここで作成するHealth checkはCellのステータスやALBの応答結果等に連動するものではありません。 あくまでもRouting controlのステートと連動するHealth checkです。
まずは、プライマリーエンドポイント用のHealth checkを作成します。
aws route53 create-health-check \ --caller-reference primary-20210810 \ --health-check-config \ Type="RECOVERY_CONTROL",RoutingControlArn="arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd"
{ "Location": "https://route53.amazonaws.com/2013-04-01/healthcheck/5b375bce-4bba-4d6f-8009-9c2cd04d746b", "HealthCheck": { "Id": "5b375bce-4bba-4d6f-8009-9c2cd04d746b", "CallerReference": "primary-20210810", "HealthCheckConfig": { "Type": "RECOVERY_CONTROL", "Inverted": false, "Disabled": false, "RoutingControlArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd" }, "HealthCheckVersion": 1 } }
続けて、セカンダリエンドポイント用のHealth checkを作成します。
aws route53 create-health-check \ --caller-reference secondary-20210810 \ --health-check-config \ Type="RECOVERY_CONTROL",RoutingControlArn="arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44"
{ "Location": "https://route53.amazonaws.com/2013-04-01/healthcheck/2a177357-56fb-4459-a653-a5c332b2fe63", "HealthCheck": { "Id": "2a177357-56fb-4459-a653-a5c332b2fe63", "CallerReference": "secondary-20210810", "HealthCheckConfig": { "Type": "RECOVERY_CONTROL", "Inverted": false, "Disabled": false, "RoutingControlArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44" }, "HealthCheckVersion": 1 } }
Routing controlのステータスがHealth checkと連動するため、Health checkのステータスはUnhealthyとなります。
Record setの作成
最後にRecord setを作成します。
今回はFailover Routing Policyを利用します。 プライマリーのレコードには、プライマリー用のRouting controlを関連付けたHealth checkを設定します。 セカンダリーも同様です。
RECORD_SETS_FILE_NAME='SafetyRule.json' cat << EOF > ${RECORD_SETS_FILE_NAME} { "Comment": "Failover Recordset to route traffic to the load balancer", "Changes": [ { "Action": "CREATE", "ResourceRecordSet": { "Name": "TicTacToe.example.com", "Type": "A", "SetIdentifier": "TicTacToe-east", "Failover": "PRIMARY", "AliasTarget": { "HostedZoneId": "Z35SXDOTRQ7X7K", "DNSName": "Ticta-TicTa-YWMTPCCQ3W7E-1302178901.us-east-1.elb.amazonaws.com", "EvaluateTargetHealth": true }, "HealthCheckId": "5b375bce-4bba-4d6f-8009-9c2cd04d746b" } }, { "Action": "CREATE", "ResourceRecordSet": { "Name": "TicTacToe.example.com", "Type": "A", "SetIdentifier": "TicTacToe-west", "Failover": "SECONDARY", "AliasTarget": { "HostedZoneId": "Z1H1FL5HABSF5", "DNSName": "Ticta-TicTa-75WLM88UNNBN-1655711362.us-west-2.elb.amazonaws.com", "EvaluateTargetHealth": true }, "HealthCheckId": "2a177357-56fb-4459-a653-a5c332b2fe63" } } ] } EOF aws route53 change-resource-record-sets \ --hosted-zone-id Z09131642IO3SMGZ86ZJR \ --change-batch file://${RECORD_SETS_FILE_NAME}
{ "ChangeInfo": { "Id": "/change/C06989663REELPFX33C6O", "Status": "PENDING", "SubmittedAt": "2021-08-12T02:35:18.265000+00:00", "Comment": "Failover Recordset to route traffic to the load balancer" } }
設定は以上です。
動作確認
Routing control
まずはRouting control関連の機能を確認します。
まず、作成したRouting controlのステータスを両方ONにします。
aws route53-recovery-cluster update-routing-control-state \ --routing-control-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd" \ --routing-control-state On \ --endpoint-url "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1" \ --region ap-northeast-1
aws route53-recovery-cluster update-routing-control-state \ --routing-control-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44" \ --routing-control-state On \ --endpoint-url "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1" \ --region ap-northeast-1
併せて、Health checkのステータスが変わったことを確認します。
aws route53-recovery-cluster get-routing-control-state \ --routing-control-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd" \ --endpoint-url "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1" \ --region ap-northeast-1
{ "RoutingControlArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd", "RoutingControlState": "On" }
aws route53-recovery-cluster get-routing-control-state \ --routing-control-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44" \ --endpoint-url "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1" \ --region ap-northeast-1
{ "RoutingControlArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44", "RoutingControlState": "On" }
Health checkを確認すると、ステータスがHealthyになっていることを確認できました。
この時点の状態を正常な状態として引き続き動作確認を進めます。
ちなみに、この状態でアプリケーションへアクセスすると、プライマリーエンドポイント側にアクセスしていることが確認できます(左上にリージョンが表示されます)。
この状態から、プライマリーエンドポイント用のRouting controlをOFFにします。
aws route53-recovery-cluster update-routing-control-state \ --routing-control-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd" \ --routing-control-state Off \ --endpoint-url "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1" \ --region ap-northeast-1
aws route53-recovery-cluster get-routing-control-state \ --routing-control-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd" \ --endpoint-url "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1" \ --region ap-northeast-1
{ "RoutingControlArn": "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/f3d7d5d672b24fbd", "RoutingControlState": "Off" }
Health checkも確認します。
アプリケーションにアクセスすると、今度はセカンダリエンドポイントにアクセスしていました。
最後に、セカンダリエンドポイント用のRouting controlをOFFにします。 するとSafety ruleに基づいてセーフガードが機能しました。 えらいぞ~。
aws route53-recovery-cluster update-routing-control-state \ --routing-control-arn "arn:aws:route53-recovery-control::xxxxxxxxxxxx:controlpanel/9749fe9143364ff496ab8e6d352a1f72/routingcontrol/749f0ac746ca4c44" \ --routing-control-state Off \ --endpoint-url "https://321b4113.route53-recovery-cluster.ap-northeast-1.amazonaws.com/v1" \ --region ap-northeast-1
An error occurred (ValidationException) when calling the UpdateRoutingControlState operation: Cannot modify control state for [9749fe9143364ff496ab8e6d352a1f72749f0ac746ca4c44] due to failed rule evaluation 9749fe9143364ff496ab8e6d352a1f721c2da713a77e46f1
Readiness check
Readiness checkの動作を確認します。
まず、Readiness checkのステータスを確認します。 以下の通り、現時点ではすべて問題なしと評価されています。
aws route53-recovery-readiness get-readiness-check-status \ --readiness-check-name alb-readiness-check
{ "Resources": [ { "LastCheckedTimestamp": "2021-08-12T03:06:30+00:00", "Readiness": "READY", "ResourceArn": "arn:aws:elasticloadbalancing:us-east-1:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-YWMTPCCQ3W7E/b6231aee3fc0f4f2" }, { "LastCheckedTimestamp": "2021-08-12T03:06:30+00:00", "Readiness": "READY", "ResourceArn": "arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-75WLM88UNNBN/2514249eff5f0a8c" } ], "Readiness": "READY", "Messages": [] }
aws route53-recovery-readiness get-readiness-check-status \ --readiness-check-name asg-readiness-check
{ "Resources": [ { "LastCheckedTimestamp": "2021-08-12T03:07:36+00:00", "Readiness": "READY", "ResourceArn": "arn:aws:autoscaling:us-east-1:xxxxxxxxxxxx:autoScalingGroup:*:autoScalingGroupName/TictactoeAppCdkStack-us-east-1-TicTacToeASGCBDED12E-7VX164PP89X6" }, { "LastCheckedTimestamp": "2021-08-12T03:07:36+00:00", "Readiness": "READY", "ResourceArn": "arn:aws:autoscaling:us-west-2:xxxxxxxxxxxx:autoScalingGroup:*:autoScalingGroupName/TictactoeAppCdkStack-us-west-2-TicTacToeASGCBDED12E-1O7BWG3Y3TL21" } ], "Readiness": "READY", "Messages": [] }
aws route53-recovery-readiness get-readiness-check-status \ --readiness-check-name ddb-readiness-check
{ "Resources": [ { "LastCheckedTimestamp": "2021-08-12T03:07:37+00:00", "Readiness": "READY", "ResourceArn": "arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/Games" } ], "Readiness": "READY", "Messages": [] }
また、評価対象のリソースが含まれるCellおよびRecovery groupのステータスも正常であることが確認できます。
aws route53-recovery-readiness get-cell-readiness-summary \ --cell-name primary-cell
{ "ReadinessChecks": [ { "Readiness": "READY", "ReadinessCheckName": "asg-readiness-check" }, { "Readiness": "READY", "ReadinessCheckName": "alb-readiness-check" } ], "Readiness": "READY" }
aws route53-recovery-readiness get-cell-readiness-summary \ --cell-name secondary-cell
{ "ReadinessChecks": [ { "Readiness": "READY", "ReadinessCheckName": "asg-readiness-check" }, { "Readiness": "READY", "ReadinessCheckName": "alb-readiness-check" } ], "Readiness": "READY" }
aws route53-recovery-readiness get-recovery-group-readiness-summary \ --recovery-group-name TicTacToe-recovery-group
{ "ReadinessChecks": [ { "Readiness": "READY", "ReadinessCheckName": "ddb-readiness-check" } ], "Readiness": "READY" }
この状態でプライマリー側のCellに含まれるAutoScaling Groupのメンバーインスタンスを削除します。
すると、ALBのReadiness checkで問題を検出しました。
aws route53-recovery-readiness get-readiness-check-status \ --readiness-check-name alb-readiness-check
{ "Resources": [ { "LastCheckedTimestamp": "2021-08-12T03:19:32+00:00", "Readiness": "NOT_READY", "ResourceArn": "arn:aws:elasticloadbalancing:us-east-1:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-YWMTPCCQ3W7E/b6231aee3fc0f4f2" }, { "LastCheckedTimestamp": "2021-08-12T03:19:32+00:00", "Readiness": "READY", "ResourceArn": "arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-75WLM88UNNBN/2514249eff5f0a8c" } ], "Readiness": "NOT_READY", "Messages": [] }
"NOT_READY"とされたリソースの詳細を確認します。 すると、"ElbV2TargetGroupsCanServeTraffic"というルールに抵触しており、"ELB does not have target groups which are all healthy."というメッセージが出力されました。
aws route53-recovery-readiness get-readiness-check-resource-status \ --readiness-check-name alb-readiness-check \ --resource-identifier "arn:aws:elasticloadbalancing:us-east-1:xxxxxxxxxxxx:loadbalancer/app/Ticta-TicTa-YWMTPCCQ3W7E/b6231aee3fc0f4f2"
{ "Rules": [ { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2CheckAzCount" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2CrossZoneEnabled" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2DeletionProtection" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2Http2Enabled" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2HttpDropInvalidHeaders" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2IdleTimeoutSeconds" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2IpAddressType" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2S3LogsEnabled" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2Scheme" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2State" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [ { "MessageText": "ELB does not have target groups which are all healthy." } ], "Readiness": "NOT_READY", "RuleId": "ElbV2TargetGroupsCanServeTraffic" }, { "LastCheckedTimestamp": "2021-08-12T03:25:33+00:00", "Messages": [], "Readiness": "READY", "RuleId": "ElbV2Type" } ], "Readiness": "NOT_READY" }
なお、AutoScaling Groupの機能でEC2インスタンスは自動的に復旧されました。 これがレジリエンスか。
併せて、関連するCellおよびRecovery groupのステータスが影響を受けていることも確認できます。
aws route53-recovery-readiness get-cell-readiness-summary \ --cell-name primary-cell
{ "ReadinessChecks": [ { "Readiness": "READY", "ReadinessCheckName": "asg-readiness-check" }, { "Readiness": "NOT_READY", "ReadinessCheckName": "alb-readiness-check" } ], "Readiness": "NOT_READY" }
Recovery groupに直接所属しているDynamoDB Tableは問題ないものの、所属するCellがNOT READYであるためRecovery groupとしてもNOT_READYとなっています。
aws route53-recovery-readiness get-recovery-group-readiness-summary \ --recovery-group-name TicTacToe-recovery-group
{ "ReadinessChecks": [ { "Readiness": "READY", "ReadinessCheckName": "ddb-readiness-check" } ], "Readiness": "NOT_READY" }
料金
料金はClusterおよびReadiness checkに対して発生します。
Route 53 Application Recovery Controller
You pay for Route 53 Application Recovery Controller based on two dimensions Readiness Checks and Clusters. You pay only for what you use and there are no upfront charges to use Route 53 Recovery Controller.
Readiness check: Readiness check audits your resources across Availability Zones or Regions to help you ensure they are prepared for a recovery. You pay $0.045 per hour for every readiness check that is configured. For example, if you have modeled an application using Route 53 Application Recovery Controller and have a readiness check for Auto Scaling Groups and another for DynamoDB tables, you will have two readiness checks configured, each charging $0.045. So, your total readiness check bill will be $0.09 per hour.
Cluster: Clusters are a set of redundant regional endpoints against which you can execute API calls to update or get the state of one or more routing controls. You pay $2.5 per hour for every cluster configured. Each cluster (maximum 2) can host multiple routing controls, which are used to trigger failovers.
Routing control(Cluster)に関しては、本当に使うべきところで使うって感じになりそうですね。
まとめ
Route 53 Application Recovery Controllerは、Readiness checkおよびRecovery controlの2つの機能を提供します。
Readiness checkを利用することで冗長化されたアプリケーションスタックが「本当に適切に冗長化されているか」確認できます。 「フェールオーバーしたけど、なんかおかしくね?」というリスクを下げる・問題に早く気づくことができそうです。 従来からSecurity HubやConfirmance Pack等でリソース自体の評価(Posture Management)は可能でしたが、冗長化されたリソースを比較するような機能はなかったので個人的には注目に値する機能だと思います。
また、Recovery controlを用いることで柔軟かつ安全なルーティング制御が可能になりました。 メンテナンス時に手動でフェールオーバーさせたり、特定のCellの応答がなんとなくおかしいときにとりあえず切り離すといった運用も容易になると思います。 コストが気になりますがかなり安心感が増すとも思うので、ミッションクリティカルなワークロードでは検討してみてもいいのではないでしょうか。
今回試してみた2つの機能は同時に利用する必要はないので、必要な機能だけを利用するのもありだと思います。 興味のある方は是非試してみてください。